#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <net/if.h>  
#include <sys/ioctl.h>  
#include <linux/can.h>  
#include <linux/can/raw.h>  
#include <sys/time.h>  
#include <sys/select.h>  
#include <errno.h>  

#define CAN_INTERFACE "can0"  
#define TIMEOUT_SEC 5  // select超时时间，单位为秒  

int main() 
{  
    int sock;  
    struct sockaddr_can addr;  
    struct ifreq ifr;  
    struct can_frame frame;  
    fd_set rfds;  
    struct timeval tv;  
    int retval;  

    // 打开SocketCAN套接字  
    if ((sock = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {  
        perror("Socket");  
        exit(EXIT_FAILURE);  
    }  

    strcpy(ifr.ifr_name, CAN_INTERFACE);  
    ioctl(sock, SIOCGIFINDEX, &ifr);  

    addr.can_family = AF_CAN;  
    addr.can_ifindex = ifr.ifr_ifindex;  

    // 绑定套接字到CAN接口  
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {  
        perror("Bind");  
        close(sock);  
        exit(EXIT_FAILURE);  
    }  

    // 初始化文件描述符集合  
    FD_ZERO(&rfds);  
    FD_SET(sock, &rfds);  

    // 设置select超时时间  
    tv.tv_sec = TIMEOUT_SEC;  
    tv.tv_usec = 0;  

    while (1) {  
        // 调用select函数监控套接字  
        retval = select(sock + 1, &rfds, NULL, NULL, &tv);  

        if (retval == -1) {  
            perror("Select");  
            close(sock);  
            exit(EXIT_FAILURE);  
        } else if (retval) {  
            // 套接字就绪，读取CAN帧  
            if (FD_ISSET(sock, &rfds)) {  
                int nbytes = read(sock, &frame, sizeof(struct can_frame));  

                if (nbytes < 0) {  
                    perror("Read");  
                } else {  
                    // 处理接收到的CAN帧  
                    printf("Received CAN frame with ID: 0x%X, Data: ", frame.can_id);  
                    for (int i = 0; i < frame.can_dlc; i++) {  
                        printf("%02X ", frame.data[i]);  
                    }  
                    printf("\n");  
                }  
            }  
        } else {  
            // 超时，没有接收到任何数据  
            printf("No data received within timeout period.\n");  
        }  

        // 重置文件描述符集合，为下一次select调用做准备  
        FD_ZERO(&rfds);  
        FD_SET(sock, &rfds);  
    }  

    close(sock);  
    return 0;  
}